package com.zhousb.deviceManager.service.impl;

import com.alibaba.excel.EasyExcel;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.zhousb.deviceManager.exception.CustomerException;
import com.zhousb.deviceManager.mapper.ImOrderMapper;
import com.zhousb.deviceManager.mapper.ImProductLogMapper;
import com.zhousb.deviceManager.mapper.ImProductMapper;
import com.zhousb.deviceManager.model.bo.ProductBo;
import com.zhousb.deviceManager.model.dto.ExportCreateDto;
import com.zhousb.deviceManager.model.dto.ProductSaveQtyDto;
import com.zhousb.deviceManager.model.entity.ImOrder;
import com.zhousb.deviceManager.model.entity.ImProduct;
import com.zhousb.deviceManager.model.entity.ImProductLog;
import com.zhousb.deviceManager.model.enums.NoticeTypeEnum;
import com.zhousb.deviceManager.model.enums.OrderStatusEnum;
import com.zhousb.deviceManager.model.enums.ProductLogOperationEnum;
import com.zhousb.deviceManager.model.so.ProductLogSo;
import com.zhousb.deviceManager.model.so.ProductSo;
import com.zhousb.deviceManager.model.so.SimpleSo;
import com.zhousb.deviceManager.model.vo.ProductExportVo;
import com.zhousb.deviceManager.model.vo.ProductLogVo;
import com.zhousb.deviceManager.model.vo.ProductVo;
import com.zhousb.deviceManager.security.JwtUser;
import com.zhousb.deviceManager.service.NoticeService;
import com.zhousb.deviceManager.service.ProductService;
import com.zhousb.deviceManager.service.SysUserService;
import com.zhousb.deviceManager.utils.AuthUtils;
import com.zhousb.deviceManager.utils.IdGenerator;
import com.zhousb.deviceManager.utils.RedisUtil;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

import static com.zhousb.deviceManager.common.Constants.WATCH_PRODUCT;
import static com.zhousb.deviceManager.model.enums.RoleEnum.STORE_MANAGER;

@Service
public class ProductServiceImpl implements ProductService {

    @Resource
    private ImProductMapper productMapper;
    @Resource
    private ImProductLogMapper productLogMapper;
    @Resource
    private ImOrderMapper orderMapper;
    @Resource
    NoticeService noticeService;
    @Resource
    SysUserService sysUserService;
    @Resource
    AuthUtils authUtils;
    @Resource
    RedisUtil redisUtil;

    @Override
    public IPage<ProductVo> page(Page<ImProduct> page, ProductSo so) {
        IPage<ProductVo> result = new Page<>(page.getCurrent(), page.getSize());
        LambdaQueryWrapper<ImProduct> queryWrapper = new LambdaQueryWrapper<>();
        List<String> keywords = new ArrayList<>();
        if (StringUtils.hasText(so.getKeyword())) {
            keywords = Arrays.asList(so.getKeyword().split(" "));
        }
        for (String keyword : keywords) {
            queryWrapper.like(ImProduct::getProductName, keyword);
        }
        if (StringUtils.hasText(so.getAfloatStatus())) {
            queryWrapper.eq(ImProduct::getAfloatStatus, Integer.parseInt(so.getAfloatStatus()));
        }


        if (StringUtils.hasText(so.getSortField()) && so.getSortType() != null && (so.getSortType().equals("ascend") || so.getSortType().equals("descend"))) {
            switch (so.getSortField()) {
                case "productName":
                    queryWrapper.orderBy(true, so.getSortType().equals("ascend"), ImProduct::getProductName);
                    break;
                case "storeNum":
                    queryWrapper.orderBy(true, so.getSortType().equals("ascend"), ImProduct::getStoreNum);
                    break;
                case "limitTime":
                    queryWrapper.orderBy(true, so.getSortType().equals("ascend"), ImProduct::getLimitTime);
                    break;
            }
        }
        List<ProductSaveQtyDto> saveProductQtyList = new ArrayList<>();
        saveProductQtyList = productMapper.listSaveProductQty();
        Map<Long, Integer> saveProductQtyMap = saveProductQtyList.stream().collect(Collectors.toMap(ProductSaveQtyDto::getProductId, ProductSaveQtyDto::getQuantity));

        page = productMapper.selectPage(page, queryWrapper);
        result.setTotal(page.getTotal());
        List<ProductVo> records = new ArrayList<>();
        records = page.getRecords().stream().map(s -> {
            ProductVo vo = new ProductVo();
            BeanUtils.copyProperties(s, vo);
            vo.setActualStoreNum(saveProductQtyMap.get(s.getId()) == null ? s.getStoreNum() : s.getStoreNum() + saveProductQtyMap.get(s.getId()));
            return vo;
        }).toList();
        result.setRecords(records);
        return result;
    }

    @Override
    public void updateStoreNum(Long productId, Integer quantity, boolean isMinus) {
        ImProduct product = productMapper.selectById(productId);
        Integer rawQuantity = product.getStoreNum();
        int resultQuantity;
        if (isMinus) {
            resultQuantity = rawQuantity - quantity;
            if (resultQuantity < 0) {
                throw new RuntimeException("库存不足");
            }
        } else {
            resultQuantity = rawQuantity + quantity;
        }
        product.setStoreNum(resultQuantity);
        productMapper.updateById(product);
    }

    @Override
    @Transactional
    public boolean create(ProductBo bo) {
        JwtUser jwtUser = authUtils.getUser();
//        LambdaQueryWrapper<ImProduct> queryWrapper = new LambdaQueryWrapper<>();
//        queryWrapper.eq(ImProduct::getProductName, bo.getProductName());
//        boolean exists = productMapper.exists(queryWrapper);
//        if (exists) {
//            throw new CustomerException("库里已有完全同名产品【" + bo.getProductName() + "】");
//        }
        ImProduct product = new ImProduct();
        BeanUtils.copyProperties(bo, product);
        product.setAfloatStatus(Integer.parseInt(bo.getAfloatStatus()));
        Long id = IdGenerator.nextId();
        product.setId(id);
        productMapper.insert(product);

        ImProductLog productLog = new ImProductLog();
        productLog.setProductId(id);
        productLog.setOperationType(ProductLogOperationEnum.INIT.getType());
        productLog.setOperation(ProductLogOperationEnum.INIT.getName());
        productLog.setQuantity(bo.getStoreNum());
        productLog.setStoreNum(bo.getStoreNum());
        productLog.setOperationTime(LocalDateTime.now());
        productLog.setOperationUserId(jwtUser.getUserId());
        productLogMapper.insert(productLog);

        String content = String.format("【%s】新建了【%s】产品【%s】，库存数量【%s】", jwtUser.getRealName(), product.getAfloatStatus().equals(0) ? "在库" : "在途", product.getProductName(), product.getStoreNum());
        noticeService.createNotice(NoticeTypeEnum.STORE_MESSAGE, content, null, sysUserService.getRoleUserMap(STORE_MANAGER.getCode()));
        return true;
    }


    @Override
    public boolean update(ProductBo bo) {
        Object object = redisUtil.hget(WATCH_PRODUCT,bo.getId().toString());
        if(object!=null){
            String productStatus = object.toString();
            if(productStatus.equals("2")){
                throw new CustomerException("产品变更");
            }
        }
        JwtUser jwtUser = authUtils.getUser();
        ImProduct product = productMapper.selectById(bo.getId());
        if (product == null) {
            throw new CustomerException("产品不存在");
        }
        Integer oldStoreNum = product.getStoreNum();
        BeanUtils.copyProperties(bo, product, "id");
        if (!product.getAfloatStatus().equals(Integer.parseInt(bo.getAfloatStatus()))) {
            if (bo.getAfloatStatus().equals("1")) {
                throw new CustomerException("不能将产品设置为【在途】");
            }
            orderMapper.updateAfloatOrder(bo.getId());
        }

        product.setAfloatStatus(Integer.parseInt(bo.getAfloatStatus()));
        productMapper.updateById(product);
        Integer newStoreNum = product.getStoreNum();

        ImProductLog productLog = new ImProductLog();
        productLog.setProductId(bo.getId());
        productLog.setOperationType(ProductLogOperationEnum.UPDATE_STORE.getType());
        productLog.setOperation(ProductLogOperationEnum.UPDATE_STORE.getName());
        productLog.setQuantity(bo.getStoreNum());
        productLog.setStoreNum(bo.getStoreNum());
        productLog.setOperationTime(LocalDateTime.now());
        productLog.setOperationUserId(jwtUser.getUserId());

        productLogMapper.insert(productLog);

        if (!newStoreNum.equals(oldStoreNum)) {
            String content = String.format("【%s】修改了【%s】产品【%s】库存，原库存数量【%s】，修改后库存数量【%s】", jwtUser.getRealName(), product.getAfloatStatus().equals(0) ? "在库" : "在途", product.getProductName(), oldStoreNum, newStoreNum);
            noticeService.createNotice(NoticeTypeEnum.STORE_MESSAGE, content, null, sysUserService.getRoleUserMap(STORE_MANAGER.getCode()));
        }

        return true;
    }

    @Override
    public boolean delete(String productId) {
        ImProduct product = productMapper.selectById(productId);
        if (product == null) {
            throw new CustomerException("产品不存在");
        }
        productMapper.deleteById(product);
        return true;
    }

    @Override
    public IPage<ProductLogVo> log(Page page, ProductLogSo so) {
        IPage<ProductLogVo> result = productLogMapper.listProductLog(page, so.getProductId());
        return result;
    }

    @Override
    public void export(ProductSo so, HttpServletResponse response) throws IOException {
        LambdaQueryWrapper<ImProduct> queryWrapper = new LambdaQueryWrapper<>();
        List<String> keywords = new ArrayList<>();
        if (StringUtils.hasText(so.getKeyword())) {
            keywords = Arrays.asList(so.getKeyword().split(" "));
        }
        for (String keyword : keywords) {
            queryWrapper.like(ImProduct::getProductName, keyword);
        }
        if (StringUtils.hasText(so.getAfloatStatus())) {
            queryWrapper.eq(ImProduct::getAfloatStatus, Integer.parseInt(so.getAfloatStatus()));
        }

        if (StringUtils.hasText(so.getSortType()) && StringUtils.hasText(so.getSortField())) {
            switch (so.getSortField()) {
                case "productName":
                    queryWrapper.orderBy(true, so.getSortType().equals("ascend"), ImProduct::getProductName);
                    break;
                case "storeNum":
                    queryWrapper.orderBy(true, so.getSortType().equals("ascend"), ImProduct::getStoreNum);
                    break;
                case "limitTime":
                    queryWrapper.orderBy(true, so.getSortType().equals("ascend"), ImProduct::getLimitTime);
                    break;
            }
        }
        List<ImProduct> products = productMapper.selectList(queryWrapper);
        List<ProductSaveQtyDto> saveProductQtyList = new ArrayList<>();
        saveProductQtyList = productMapper.listSaveProductQty();
        Map<Long, Integer> saveProductQtyMap = saveProductQtyList.stream().collect(Collectors.toMap(ProductSaveQtyDto::getProductId, ProductSaveQtyDto::getQuantity));

        List<ProductExportVo> exportData = new ArrayList<>();
        exportData = products.stream().map(s -> {
            ProductExportVo vo = new ProductExportVo();
            vo.setProductName(s.getProductName());
            vo.setLimitTime(s.getLimitTime());
            vo.setAfloatStatus(s.getAfloatStatus() == 1 ? "在途" : "在库");
            vo.setStoreName(s.getStoreNum());
            vo.setActualStoreName(saveProductQtyMap.get(s.getId()) == null ? s.getStoreNum() : s.getStoreNum() + saveProductQtyMap.get(s.getId()));
            return vo;
        }).toList();

        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setCharacterEncoding("utf-8");
        // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
        String fileName = "123";
        response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
        EasyExcel.write(response.getOutputStream(), ProductExportVo.class).sheet("库存信息").doWrite(exportData);

    }

    @Override
    public boolean watch(String productId) {
        redisUtil.hset(WATCH_PRODUCT, productId, 1);
        return true;
    }

    @Override
    public boolean unwatch(String productId) {
        redisUtil.hdel(WATCH_PRODUCT, productId);
        return true;
    }
}
